/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo
 * All rights reserved.
 */
package ac.jp.u_tokyo.SyncLib;

import com.sun.org.apache.bcel.internal.generic.GETSTATIC;

public class SwitchCombinator extends StaticCombinatorBase
{
	int _paraCount;
	int _syncCount;
	
	private int getLastInvoked() {
		return (Integer) getAttribute(0);
	}

	private void setLastInvoked(int lastSyncIndex) {
		setAttribute(0, lastSyncIndex);
	}
	
	
	private Object[] getParaValues() {
		Object[] result = new Object[_paraCount];
		for (int i = 0; i < _paraCount; i++) {
			result[i] = getAttribute(i + 1);
		}
		return result;
	}
	
//	@Override
//	public boolean isModConcerned(int index, Mod mod) throws ModTypeUnsupportedException
//	{
//		try
//		{
//			return getSync(getLastInvoked()).isModConcerned(index, mod);
//		}
//		catch (ModTypeUnsupportedException e)
//		{
//			return super.isModConcerned(index, mod);
//		}
//	}

	private void modifyParaValues(Mod[] mods) {
		for (int i = 0; i < _paraCount; i++) {
			modifyAttribute(i + 1, mods[i]);
		}
	}

	private void modifyParaValuesInResync(Mod[] mods, Object[] values) {
		Object[] paraValues = getParaValues();
		for (int i = 0; i < _paraCount; i++) {
			modifyAttribute(i + 1, Value2Mod.findMod(paraValues[i], mods[i].apply(values[i])));
		}
	}

	
	public SwitchCombinator(Sync[] syncs) {
		super(createState(syncs[0].getParaCount()), syncs);
		_paraCount = syncs[0].getParaCount();
		_syncCount = syncs.length;
	}
	
	private static Object[] createState(int syncCount) {
		Integer lastInvoked = 0;
		Object[] result = new Object[syncCount + 1];
		result[0] = lastInvoked;
//		for (int i = 0; i < initialValues.length; i++)
//		{
//			result[i + 1] = Helper.deepCopy(initialValues[i]);
//		}
		return result;
	}

//	public Object[] getInitialValues()
//	{
//		return getSync(0).getInitialValues();
//	}

	public int getParaCount()
	{
		return _paraCount;
	}

	@Override
	protected Mod[] doResynchronize(Object[] values, Mod[] modifications)
			throws SynchronizationFailedException
	{
		for (int i = 0; i < _syncCount; i++) {
			try
			{
				Mod[] mods = invokeResync(i, values, modifications);
				modifyParaValuesInResync(mods, values);
				setLastInvoked(i);
				return mods;
			}
			catch (SynchronizationFailedException e2)
			{
			}
		}
		throw new SynchronizationFailedException();
	}

	@Override
	protected Mod[] doSynchronize(Mod[] modifications)
			throws SynchronizationFailedException
	{
		try {
			Mod[] mods = invokeSync(getLastInvoked(), modifications);
			modifyParaValues(mods);
			return mods;
		}
		catch (SynchronizationFailedException e) {
			for (int i = 0; i < _syncCount; i++) {
				if (i == getLastInvoked()) continue;
				try
				{
					Mod[] mods = invokeResync(i, getParaValues(), modifications);
					setLastInvoked(i);
					modifyParaValues(mods);
					return mods;
				}
				catch (SynchronizationFailedException e2)
				{
				}
			}
		}
		throw new SynchronizationFailedException();
	}

	@Override
	public String toString()
	{
		return "SwitchCombinator@" + hashCode();
	}

}
